package cn.e4j.modular.oa.ws.common;

import cn.e4j.core.dto.Dtos;
import cn.e4j.core.dto.impl.Dto;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.tree.DefaultElement;
import org.dom4j.tree.DefaultText;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.soap.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;

public abstract class SoapService {
    private static Logger logger = LoggerFactory.getLogger(SoapService.class);
    // 创建SOAP连接，发送请求
    public String callSoapWs(String soapEndpointUrl,String soapAction,Dto inDto) throws TimeoutException{
//        boolean canConnect = wsConnectTest();
//        if(!canConnect) {
//            throw new TimeoutException("SOAP连接超时");
//        }
        String resStr = null;
        try {
            // Create SOAP Connection
            SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConnection = soapConnectionFactory.createConnection();

            SOAPMessage soapResponse = soapConnection.call(this.createSOAPRequest(soapAction,inDto), soapEndpointUrl);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            soapResponse.writeTo(out);
            resStr = new String(out.toByteArray(), StandardCharsets.UTF_8);
            logger.info("Response SOAP Message: ");
            logger.info(resStr);
            soapConnection.close();
        } catch (Exception e) {
            logger.error("Error occurred while sending SOAP Request to Server");
            e.printStackTrace();
        }
        return resStr;
    }

    // 创建SOAP请求
    private SOAPMessage createSOAPRequest(String soapAction,Dto inDto) throws Exception {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();

        // SOAP Envelope
        SOAPEnvelope envelope = soapPart.getEnvelope();
        String serverURI = "http://webservice.review.km.kmss.landray.com/";
        envelope.addNamespaceDeclaration("web", serverURI);

        SOAPBody soapBody = envelope.getBody();
        this.createBody(soapBody,inDto);
        MimeHeaders headers = soapMessage.getMimeHeaders();
        headers.addHeader("SOAPAction", soapAction);

        soapMessage.saveChanges();

        logger.info("Request SOAP Message: ");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        soapMessage.writeTo(out);
        logger.info(new String(out.toByteArray(), StandardCharsets.UTF_8));

        return soapMessage;
    }

    // 解析OA xml响应内容
    public static final Dto parseSoapRes(String xmlStr) {
        return parseSoapRes(xmlStr,false);
    }

    /**
     *
     * @param xmlStr 需要解析的字符串
     * @param isJson <return></return>的返回内容是否为json，不传默认为false
     * @return Dto
     * isJson为 false: dto.getString("text");
     * isJson为 true : (JSONObject)dto.get("json");
     */
    public static final Dto parseSoapRes(String xmlStr,boolean isJson) {
        Dto outDto = Dtos.newDto();
        String strTitle = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
        Document document = null;
        try {
            if (xmlStr.indexOf("<?xml") < 0)
                xmlStr = strTitle + xmlStr;
            document = DocumentHelper.parseText(xmlStr);
        } catch (DocumentException e) {
            logger.error("==请注意:==\n将XML格式的字符串转换为XML DOM对象时发生错误啦!" + "\n详细错误信息如下:");
            e.printStackTrace();
        }
        List list = ((DefaultElement)document.selectNodes("//return").get(0)).content();
        if (isJson) { // 返回的是json格式
            StringBuilder sb = new StringBuilder();
            list.forEach(resChar -> {
                sb.append(((DefaultText) resChar).getText());
            });
            String resStr = sb.toString();
            if(resStr.indexOf("&quot") > 0) {
                resStr = resStr.replaceAll("&quot;","\"");
            }
            JSONObject jsonObject = JSON.parseObject(resStr);
            outDto.put("json",jsonObject);
        }else {
            String resStr = ((DefaultText) list.get(0)).getText();
            outDto.put("text",resStr);
        }
        return outDto;
    }

    // 拼接请求参数，子类必须实现这个方法
    public abstract void createBody(SOAPBody soapBody,Dto dto) throws SOAPException;

    private boolean wsConnectTest(){
        boolean canConnect = true;
        int timeout = 5000;
        InetAddress[] addresses;
        try {
            addresses = InetAddress.getAllByName("192.168.1.234");
            for (InetAddress address : addresses) {

                if (address.isReachable(timeout))
                    logger.info(address+ " is reachable" );
                else{
                    canConnect = false;
                    logger.error(address + " could not be connected");
                }
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return canConnect;
    }
}
